home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Examples / Scrolling - Multiple Layers / Multiple Layers Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  22.4 KB  |  796 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. // Multiple Layers Demo.c
  3. //
  4. // By Vern Jensen. Just a slightly modified version of the Scrolling Demo.
  5. ///--------------------------------------------------------------------------------------
  6. #ifndef __RESOURCES__
  7. #include <Resources.h>
  8. #endif
  9.  
  10.  
  11. #include <SWFPSReport.h>
  12. #include <SWIncludes.h>
  13. #include <SWGameUtils.h>
  14.  
  15. #include "SWApplication.h"
  16. #include "Multiple Layers Demo.h"
  17.  
  18.  
  19. #define    kFullScreenWindow            true        // Makes window larger than 512x384.
  20. #define kDoubleSize                    true        // Doubles size of extraBackFrameP
  21. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  22. #define    kInterlacedMode                false        // Skips every other line
  23. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  24. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  25.  
  26. #define kMaxWidth                    640            // max window width in full-screen mode
  27. #define kMaxHeight                    480            // max window height
  28.  
  29. #define    kSpriteMoveDelta            20            // Try 5, 10, 20, or 40
  30. #define kDiamondSpace                8            // How far apart the diamonds are spaced
  31.                                                 // (try 1!)
  32.  
  33. #define kSpriteMoveDistance            80            // How far the sprite can move from
  34.                                                 // the center of the screen, in pixels.
  35.                                                 // Try making this value higher!
  36.  
  37.     // Number of ticks to wait before changing tile image; 0 = change every frame
  38. #define kDiamondFrameRate            8            // How often diamond tiles change frames
  39. #define kWallFrameRate                120            // How often wall changes frames
  40.  
  41. #define kBWPictResIDOffset            100
  42. #define kTileWidth                    40
  43. #define kTileHeight                    40
  44. #define kTileMapRows                100
  45. #define kTileMapCols                150
  46.  
  47. #define kStartRow                    5            // Starting position of sprite
  48. #define kStartCol                    5            // in tile col and row
  49.  
  50.  
  51. #define    kLeftArrowKey                0x7B
  52. #define    kRightArrowKey                0x7C
  53. #define    kDownArrowKey                0x7D
  54. #define    kUpArrowKey                    0x7E
  55.  
  56. #define    kLeftKeyPad                    0x56
  57. #define    kRightKeyPad                0x58
  58. #define    kDownKeyPad                    0x54
  59. #define    kUpKeyPad                    0x5B
  60.  
  61. #define kEscKey                        0x35
  62.  
  63.  
  64. #define kNoKey                        0
  65. #define kLeftKey                    1
  66. #define kUpKey                        2
  67. #define kRightKey                    3
  68. #define kDownKey                    4
  69.  
  70.  
  71. enum tileIDs
  72. {
  73.     kWallTile,
  74.     kLastWallTile,
  75.     kGrassTile,
  76.     kBlackTile,
  77.     kFirstDiamondTile,
  78.     kMiddleDiamondTile,
  79.     kLastDiamondTile,
  80.     kWireTile,
  81.     
  82.     kMaxNumTiles
  83. };
  84.  
  85.  
  86.  
  87. /***********/
  88. /* Globals */
  89. /***********/
  90.  
  91. SpriteWorldPtr        gSpriteWorldP;
  92. SpriteLayerPtr        gSpriteLayerP, gNonScrollingSpriteLayerP;
  93. TileMapStructPtr    gTileMapStructP, gSecondTileMapStructP;
  94. TileMapPtr            gTileMap;
  95. SpritePtr            gSimpleSpriteP, gDiamondMeterSpriteP;
  96. DrawProcPtr            gSpriteDrawProc;
  97. WindowPtr            gWindowP;
  98. Rect                gScreenMidRect;
  99.  
  100. long                gNumDiamondsInMap = 0;    // Number of diamonds in the TileMap
  101. long                gNumDiamonds = 0;        // Number of diamonds sprite has collected
  102.  
  103. struct moveKeys        // Keeps track of which keys are up and which are down
  104. {
  105.     Boolean    up;
  106.     Boolean    right;
  107.     Boolean    down;
  108.     Boolean    left;
  109. } gKeys;
  110.  
  111.  
  112. ///--------------------------------------------------------------------------------------
  113. // Main
  114. ///--------------------------------------------------------------------------------------
  115.  
  116. void    main( void )
  117. {
  118.     Initialize(kNumberOfMoreMastersCalls);
  119.  
  120.     if (SWHasSystem7())
  121.     {
  122.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  123.         SetCursor(*GetCursor(watchCursor));
  124.         HideControlStrip();
  125.         
  126.         SWSetCleanUpFunction(MyCleanUpFunction);
  127.         
  128.         CreateSpriteWorld();
  129.         SetUpTiling();
  130.         CreateBallSprite();
  131.         CreateDiamondMeterSprite();
  132.         
  133.         SetCursor(&qd.arrow);
  134.         HideCursor();
  135.         
  136.         SetUpAnimation();
  137.         RunAnimation();
  138.         ShutDown();
  139.         
  140.         RestoreControlStrip();    // Call this after using HideControlStrip before quitting
  141.         RestoreEventMask();        // Call this after using AllowKeyUpEvents before quitting
  142.     }
  143.     else
  144.     {
  145.         CantRunOnThisMachine();
  146.     }
  147. }
  148.  
  149.  
  150. ///--------------------------------------------------------------------------------------
  151. // CreateSpriteWorld
  152. ///--------------------------------------------------------------------------------------
  153.  
  154. void    CreateSpriteWorld( void )
  155. {
  156.     Rect        offscreenRect, worldRect, windRect;
  157.     RgnHandle    mBarUpdateRgn;
  158.     OSErr        err;
  159.     
  160.     gWindowP = GetNewCWindow(kWindowResID, NULL, (WindowPtr)-1L);
  161.     
  162.     if (gWindowP != NULL)
  163.     {
  164.         if (kFullScreenWindow == true)
  165.         {
  166.             SizeWindow(gWindowP, SW_MIN(qd.screenBits.bounds.right, kMaxWidth), 
  167.                     SW_MIN(qd.screenBits.bounds.bottom, kMaxHeight), false);
  168.             MoveWindow(gWindowP, 0, 0, false);
  169.         }
  170.         
  171.             // Center window in screen
  172.         windRect = gWindowP->portRect;
  173.         CenterRect(&windRect, &qd.screenBits.bounds);
  174.         
  175.             // Make sure window is aligned to long-word boundaries (for 8-bit mode)
  176.         windRect.left = windRect.left>>2<<2;
  177.         
  178.         MoveWindow(gWindowP, windRect.left, windRect.top, false);
  179.         
  180.         ShowWindow(gWindowP);
  181.         SetPort(gWindowP);
  182.         mBarUpdateRgn = SWHideMenuBar(gWindowP); // Must be done *after* showing window!
  183.         EraseRgn(mBarUpdateRgn);
  184.         
  185.         if (kInterlacedMode)
  186.             PaintRect(&gWindowP->portRect);    // Blacken window for Interlaced mode
  187.     }
  188.     else
  189.         CantFindResource();
  190.     
  191.     
  192.     err = SWEnterSpriteWorld();
  193.     FatalError(err);
  194.     
  195.     
  196.     worldRect = gWindowP->portRect;
  197.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  198.     
  199.     
  200.         // Set size of offscreen area
  201.     offscreenRect = worldRect;
  202.     OffsetRect(&offscreenRect, -offscreenRect.left, -offscreenRect.top);
  203.     
  204.  
  205.         // Make offscreen area evenly divisible by tile width & height
  206.     if ( (offscreenRect.right/kTileWidth)*kTileWidth != offscreenRect.right)
  207.         offscreenRect.right = (offscreenRect.right/kTileWidth)*kTileWidth + kTileWidth;
  208.     
  209.     if ( (offscreenRect.bottom/kTileHeight)*kTileHeight != offscreenRect.bottom)
  210.         offscreenRect.bottom = (offscreenRect.bottom/kTileHeight)*kTileHeight + kTileHeight;
  211.     
  212.         // Create the scrolling sprite world
  213.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  214.             &worldRect, &offscreenRect, 0);
  215.     FatalError(err);
  216.     
  217.         // Create the sprite layers
  218.     err = SWCreateSpriteLayer(&gSpriteLayerP);
  219.     FatalError(err);
  220.     err = SWCreateSpriteLayer(&gNonScrollingSpriteLayerP);
  221.     FatalError(err);
  222.     
  223.         // Add them to the world
  224.     SWAddSpriteLayer(gSpriteWorldP, gSpriteLayerP);                    // Bottom
  225.     SWAddSpriteLayer(gSpriteWorldP, gNonScrollingSpriteLayerP);        // Top
  226.     
  227.     
  228.     gSpriteDrawProc = SWStdSpriteDrawProc;
  229.     
  230.         // Determine what DrawProcs to use
  231.     if (gSpriteWorldP->pixelDepth >= 8)        // 8-bit, 16-bit, or 32-bit, for 68k and PPC
  232.     {
  233.         gSpriteDrawProc = BlitPixieMaskDrawProc;
  234.         SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieRectDrawProc);
  235.         SWSetDoubleRectDrawProc(gSpriteWorldP, BlitPixieDoubleRectDrawProc);
  236.         SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixiePartialMaskDrawProc);
  237.     }
  238.     else if (SW_68K)    // Use AllBit blitters when in depths lower than 8-bits on 68k.
  239.     {
  240.         gSpriteDrawProc = BlitPixieAllBitMaskDrawProc;
  241.         SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  242.         SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  243.         SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  244.     }
  245. }
  246.     
  247.     
  248. ///--------------------------------------------------------------------------------------
  249. // SetUpTiling
  250. ///--------------------------------------------------------------------------------------
  251.  
  252. void    SetUpTiling( void )    
  253. {
  254.     TileMapPtr        tileMap;
  255.     short            row, col;
  256.     OSErr            err;
  257.     
  258.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  259.     FatalError(err);
  260.     
  261.     err = SWCreateTileMap(&gTileMapStructP, kTileMapRows, kTileMapCols);
  262.     FatalError(err);
  263.     
  264.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP, 0);
  265.     gTileMap = gTileMapStructP->tileMap;
  266.  
  267.         // Load first set of tiles
  268.     err = SWLoadTilesFromPictResource(
  269.         gSpriteWorldP, 
  270.         kWallTile,                // startTileID 
  271.         kBlackTile,                // endTileID
  272.         200,                    // pictResID
  273.         0,                        // maskResID
  274.         kNoMask,                // maskType
  275.         kMaskIsNotPartialMask,    // partialMask?
  276.         0,                        // horizBorderWidth
  277.         0);                        // vertBorderHeight
  278.     FatalError(err);
  279.     
  280.         // Load self-masked diamond tiles
  281.     err = SWLoadTilesFromPictResource(
  282.         gSpriteWorldP, 
  283.         kFirstDiamondTile,        // startTileID 
  284.         kLastDiamondTile,        // endTileID
  285.         201,                    // pictResID
  286.         201,                    // maskResID (same as pictResID)
  287.         kFatMask,                // maskType
  288.         kMaskIsNotPartialMask,    // partialMask?
  289.         0,                        // horizBorderWidth
  290.         0);                        // vertBorderHeight
  291.     FatalError(err);
  292.     
  293.         // Load the wire tile
  294.     err = SWLoadTileFromCicnResource(
  295.         gSpriteWorldP, 
  296.         kWireTile,                // tileID
  297.         131,                     // CICN resource ID
  298.         kFatMask,                // maskType
  299.         kMaskIsNotPartialMask);    // partialMask?
  300.     FatalError(err);
  301.  
  302.     
  303.         // Set up tileMap
  304.     for (row = 0; row < kTileMapRows; row++)
  305.     {
  306.         for (col = 0; col < kTileMapCols; col++)
  307.         {
  308.             if (row == 0 || col == 0 || row == kTileMapRows-1 || col == kTileMapCols-1)
  309.                 gTileMap[row][col] = kWallTile;
  310.             else if (row > kTileMapRows / 2)
  311.                 gTileMap[row][col] = -1;
  312.             else if ((row/kDiamondSpace)*kDiamondSpace == row && 
  313.                      (col/kDiamondSpace)*kDiamondSpace == col)
  314.             {
  315.                 gTileMap[row][col] = kFirstDiamondTile;
  316.                 gNumDiamondsInMap++;
  317.             }
  318.             else
  319.                 gTileMap[row][col] = kGrassTile;
  320.         }
  321.     }
  322.     
  323.  
  324.     
  325.         // Create the second tileMap
  326.     err = SWCreateTileMap(&gSecondTileMapStructP, kTileMapRows, kTileMapCols);
  327.     FatalError(err);
  328.     
  329.     SWInstallTileMap(gSpriteWorldP, gSecondTileMapStructP, 1);
  330.     tileMap = gSecondTileMapStructP->tileMap;
  331.     
  332.         // Set up tileMap
  333.     for (row = 0; row < kTileMapRows; row++)
  334.     {
  335.         for (col = 0; col < kTileMapCols; col++)
  336.         {
  337.             if (col > kTileMapCols / 2)
  338.                 tileMap[row][col] = kWireTile;
  339.             else
  340.                 tileMap[row][col] = -1;
  341.         }
  342.     }
  343. }
  344.  
  345.  
  346. ///--------------------------------------------------------------------------------------
  347. // CreateBallSprite
  348. ///--------------------------------------------------------------------------------------
  349.  
  350. void    CreateBallSprite( void )
  351. {
  352.     OSErr    err;
  353.     
  354.         // Create the ball sprite
  355.     err = SWCreateSpriteFromCicnResource(gSpriteWorldP, &gSimpleSpriteP, NULL, 
  356.             129, 1, kFatMask);    
  357.     FatalError(err);
  358.     
  359.         // Set up the ball sprite
  360.     SWAddSprite(gSpriteLayerP, gSimpleSpriteP);
  361.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  362.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  363.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  364.     SWSetSpriteDrawProc(gSimpleSpriteP, gSpriteDrawProc);
  365. }
  366.  
  367.  
  368. ///--------------------------------------------------------------------------------------
  369. // CreateDiamondMeterSprite
  370. ///--------------------------------------------------------------------------------------
  371.  
  372. void    CreateDiamondMeterSprite( void )
  373. {
  374.     OSErr        err;
  375.     
  376.         // Create the diamond meter sprite
  377.     err = SWCreateSpriteFromPictResource(gSpriteWorldP,
  378.                 &gDiamondMeterSpriteP, 
  379.                 NULL,            // pointer to memory for sprite
  380.                 202,             // picture resource id
  381.                 202,            // mask resource id
  382.                 1,                 // max frames
  383.                 kFatMask);        // mask type
  384.     FatalError(err);
  385.  
  386.     SWAddSprite(gNonScrollingSpriteLayerP, gDiamondMeterSpriteP);
  387.     SWSetSpriteDrawProc(gDiamondMeterSpriteP, gSpriteDrawProc);
  388.     SWSetSpriteMoveProc(gDiamondMeterSpriteP, DiamondMeterSpriteMoveProc);
  389.     SWSetSpriteLocation(gDiamondMeterSpriteP, 10, 10);
  390.     
  391.         // Mark this layer as a non-scrolling layer
  392.     SWSetLayerAsNonScrolling(gNonScrollingSpriteLayerP, true);
  393. }
  394.  
  395.  
  396. ///--------------------------------------------------------------------------------------
  397. // SetUpAnimation
  398. ///--------------------------------------------------------------------------------------
  399.  
  400. void    SetUpAnimation( void )
  401. {
  402.     Rect        moveBoundsRect, extraBackRect;
  403.     short        row, col;
  404.     PicHandle    backPictH;
  405.     OSErr        err;
  406.     
  407.     SWLockSpriteWorld(gSpriteWorldP);
  408.     
  409.         // Set up data used by the SmoothScrollingWorldMoveProc
  410.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  411.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  412.     
  413.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  414.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  415.     SWSetCleanUpSpriteWorld(gSpriteWorldP);
  416.     
  417.         // movement boundary = size of tileMap
  418.     SetRect(&moveBoundsRect, 0,0, kTileMapCols * kTileWidth, kTileMapRows * kTileHeight);
  419.     
  420.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  421.     SWSetScrollingWorldMoveProc(gSpriteWorldP, SmoothScrollingWorldMoveProc, gSimpleSpriteP);
  422.     
  423.     SWSetSpriteLayerUnderTileLayer(gSpriteLayerP, 1);
  424.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  425.     
  426.         // Move visScrollRect to starting sprite position
  427.     SWMoveVisScrollRect(gSpriteWorldP, 
  428.         gSpriteWorldP->followSpriteP->destFrameRect.left - gSpriteWorldP->backRect.right/2,
  429.         gSpriteWorldP->followSpriteP->destFrameRect.top - gSpriteWorldP->backRect.bottom/2);
  430.     
  431.         // Set starting position of diamond meter sprite
  432.     DiamondMeterSpriteMoveProc(gDiamondMeterSpriteP);
  433.  
  434.     SWSetTileMaskDrawProc(gSpriteWorldP, gSpriteDrawProc);
  435.     
  436.     if (kInterlacedMode)
  437.     {
  438.         SWSetFrameInterlacingMode(gSpriteWorldP->workFrameP, true, kSkipOddLines);
  439.         SWSetFrameInterlacingMode(gSpriteWorldP->windowFrameP, true, kSkipOddLines);
  440.         
  441.         SWSetPortToWorkArea(gSpriteWorldP);
  442.         PaintRect(&gSpriteWorldP->backRect);
  443.     }
  444.     
  445.         // Make sure CopyBits, if used, doesn't try to colorize things
  446.     SWSetPortToWindow(gSpriteWorldP);
  447.     ForeColor(blackColor);
  448.     BackColor(whiteColor);
  449.     
  450.     backPictH = GetPicture(128);    // Color pict
  451.  
  452.     if (backPictH == nil)
  453.         FatalError(-1);
  454.     
  455.     extraBackRect = (**(backPictH)).picFrame;
  456.     
  457.     if (kDoubleSize)
  458.     {
  459.         extraBackRect.right *= 2;
  460.         extraBackRect.bottom *= 2;
  461.     }
  462.     
  463.     err = SWCreateExtraBackFrame(gSpriteWorldP, &extraBackRect);
  464.     FatalError(err);
  465.     SWLockFrame(gSpriteWorldP->extraBackFrameP);
  466.     SWSetPortToExtraBackFrame(gSpriteWorldP);
  467.     DrawPicture(backPictH, &extraBackRect);
  468.     ReleaseResource((Handle)backPictH);
  469.     
  470.         // Erase the tile directly beneath the Sprite's starting position
  471.     row = gSimpleSpriteP->destFrameRect.top / kTileHeight;
  472.     col = gSimpleSpriteP->destFrameRect.left / kTileWidth;
  473.     gTileMap[row][col] = -1;
  474.  
  475.     SWDrawTilesInBackground(gSpriteWorldP);
  476.     SWUpdateScrollingSpriteWorld(gSpriteWorldP, true);
  477. }
  478.  
  479.  
  480. ///--------------------------------------------------------------------------------------
  481. //  RunAnimation
  482. ///--------------------------------------------------------------------------------------
  483.  
  484. void    RunAnimation( void )
  485. {
  486.     unsigned long        frames;
  487.         
  488.     frames = 0;
  489.     StartTimer();
  490.     
  491.     
  492.     while (!Button())
  493.     {
  494.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  495.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  496.         
  497.         if (gSpriteWorldP->frameHasOccurred)
  498.             frames++;
  499.     }
  500.     
  501.     SWShowMenuBar(gWindowP);
  502.     ShowResults(frames);
  503. }
  504.  
  505.  
  506. ///--------------------------------------------------------------------------------------
  507. //  ShutDown (clean up and dispose of the SpriteWorld)
  508. ///--------------------------------------------------------------------------------------
  509.  
  510. void    ShutDown( void )
  511. {
  512.     SWDisposeSpriteWorld(&gSpriteWorldP);
  513.     SWDisposeTileMap(&gTileMapStructP);            // SWDisposeSpriteWorld will not 
  514.     SWDisposeTileMap(&gSecondTileMapStructP);    // dispose our TileMaps for us.
  515.     SWExitSpriteWorld();
  516.     
  517.     FlushEvents(everyEvent, 0);
  518.     InitCursor();
  519. }
  520.  
  521.  
  522. ///--------------------------------------------------------------------------------------
  523. //  MyCleanUpFunction - called if an error occurs, to clean up before quitting
  524. ///--------------------------------------------------------------------------------------
  525.  
  526. void    MyCleanUpFunction( void )
  527. {
  528.     SWShowMenuBar(gWindowP);
  529.     
  530.     RestoreControlStrip();
  531.     RestoreEventMask();    
  532. }
  533.  
  534.  
  535. #pragma mark -
  536. ///--------------------------------------------------------------------------------------
  537. //  TileChangeProc
  538. ///--------------------------------------------------------------------------------------
  539.  
  540. SW_FUNC void TileChangeProc(
  541.     SpriteWorldPtr spriteWorldP)
  542. {
  543.     short            curImage;
  544.     static short    wallDelay = 0, diamondDelay = 0;
  545.     static short    oldTicks = 0;
  546.     short            ticksPassed, ticks;
  547.     
  548.         // Initialize oldTicks the first time this function is called
  549.     if (oldTicks == 0)
  550.         oldTicks = TickCount();
  551.     
  552.     ticks = TickCount();
  553.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  554.     oldTicks = ticks;
  555.     
  556.         // kWallTile
  557.     wallDelay += ticksPassed;
  558.     if (wallDelay >= kWallFrameRate)
  559.     {
  560.         curImage = spriteWorldP->curTileImage[kWallTile];
  561.         if (curImage < kLastWallTile)
  562.             curImage++;
  563.         else
  564.             curImage = kWallTile;
  565.         
  566.         SWChangeTileImage(spriteWorldP, kWallTile, curImage);
  567.         wallDelay = 0;
  568.     }
  569.     
  570.     
  571.         // kDiamondTile
  572.     diamondDelay += ticksPassed;
  573.     if (diamondDelay >= kDiamondFrameRate)
  574.     {
  575.         curImage = spriteWorldP->curTileImage[kFirstDiamondTile];
  576.         if (curImage < kLastDiamondTile)
  577.             curImage++;
  578.         else
  579.             curImage = kFirstDiamondTile;
  580.         
  581.         SWChangeTileImage(spriteWorldP, kFirstDiamondTile, curImage);
  582.         diamondDelay = 0;
  583.     }
  584. }
  585.  
  586.  
  587. ///--------------------------------------------------------------------------------------
  588. //  KeySpriteMoveProc
  589. ///--------------------------------------------------------------------------------------
  590.  
  591. SW_FUNC void KeySpriteMoveProc(SpritePtr srcSpriteP)
  592. {
  593.     short        row, col;
  594.     short        rowDelta, colDelta;
  595.     short        tile;
  596.     
  597.     UpdateKeys();    // Put the latest key values in the keys structure
  598.     
  599.     
  600.     row = SWGetSpriteVertLoc(srcSpriteP) / kTileHeight;
  601.     col = SWGetSpriteHorizLoc(srcSpriteP) / kTileWidth;
  602.  
  603.     if (row * kTileHeight == SWGetSpriteVertLoc(srcSpriteP) &&
  604.         col * kTileWidth == SWGetSpriteHorizLoc(srcSpriteP))
  605.     {        
  606.         rowDelta = 0;
  607.         colDelta = 0;
  608.         
  609.         if (gKeys.left)
  610.             colDelta = -1;
  611.         else if (gKeys.right)
  612.             colDelta = 1;
  613.         else if (gKeys.up)
  614.             rowDelta = -1;
  615.         else if (gKeys.down)
  616.             rowDelta = 1;
  617.         
  618.         tile = gTileMap[row + rowDelta][col + colDelta];
  619.         
  620.         if (tile != kWallTile)
  621.         {
  622.             srcSpriteP->vertMoveDelta = rowDelta * kSpriteMoveDelta;
  623.             srcSpriteP->horizMoveDelta = colDelta * kSpriteMoveDelta;
  624.         }
  625.         else
  626.         {
  627.             srcSpriteP->vertMoveDelta = 0;
  628.             srcSpriteP->horizMoveDelta = 0;
  629.         }
  630.     }
  631.     
  632.     if (srcSpriteP->vertMoveDelta || srcSpriteP->horizMoveDelta)
  633.     {
  634.         SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  635.         
  636.             // Determine if the sprite is completely within the grid after moving
  637.         row = SWGetSpriteVertLoc(srcSpriteP) / kTileHeight;
  638.         col = SWGetSpriteHorizLoc(srcSpriteP) / kTileWidth;
  639.  
  640.         if (row * kTileHeight == SWGetSpriteVertLoc(srcSpriteP) &&
  641.             col * kTileWidth == SWGetSpriteHorizLoc(srcSpriteP))
  642.         {
  643.                 // We're aligned with the grid, so do things normally
  644.             tile = gTileMap[row][col];
  645.         
  646.                 // Leave black trail behind sprite
  647.             if (tile == kGrassTile || tile == kFirstDiamondTile)
  648.                 SWDrawTile(gSpriteWorldP, 0, row, col, -1);    // kBlackTile
  649.  
  650.             if (tile == kFirstDiamondTile)
  651.             {
  652.                 gNumDiamonds++;            // Increase number of diamonds sprite has collected
  653.                 UpdateDiamondMeter();    // Update meter
  654.             }
  655.         }
  656.         else    
  657.         {
  658.                 // We're not aligned with the grid, so erase the piece of grass
  659.                 // tile the Sprite has just moved over, if it just ran over some grass.
  660.             if (srcSpriteP->horizMoveDelta > 0)
  661.                 col++;
  662.             else if (srcSpriteP->vertMoveDelta > 0)
  663.                 row++;
  664.             
  665.             if (gTileMap[row][col] == kGrassTile)
  666.             {
  667.                 gTileMap[row][col] = -1;
  668.             
  669.                     // I'm breaking a rule here by calling an undocumented function.
  670.                     // It is not recommended that you do this in your own code, but is
  671.                     // necessary in this case for the effect I want to achieve.
  672.                 (*gSpriteWorldP->tileRectDrawProc)(gSpriteWorldP, &srcSpriteP->destFrameRect, false);
  673.                 SWWrapRectToWorkArea(gSpriteWorldP, &srcSpriteP->destFrameRect);
  674.                 gTileMap[row][col] = kGrassTile;
  675.             }
  676.         }
  677.     }
  678. }
  679.  
  680.  
  681. ///--------------------------------------------------------------------------------------
  682. //  DiamondMeterSpriteMoveProc - not installed as a MoveProc, but called directly
  683. ///--------------------------------------------------------------------------------------
  684.  
  685. SW_FUNC void DiamondMeterSpriteMoveProc(SpritePtr srcSpriteP)
  686. {
  687.         // Move sprite to top-left corner of current visScrollRect location
  688.     SWMoveSprite(srcSpriteP, 
  689.         gSpriteWorldP->visScrollRect.left + 10, 
  690.         gSpriteWorldP->visScrollRect.top + 10);
  691. }
  692.  
  693.  
  694. ///--------------------------------------------------------------------------------------
  695. //  UpdateDiamondMeter - change the meter Sprite's image and mask
  696. ///--------------------------------------------------------------------------------------
  697.  
  698. SW_FUNC void UpdateDiamondMeter( void )
  699. {
  700.     double    percent;
  701.     Rect    meterRect;
  702.     
  703.     percent = (double)gNumDiamonds / gNumDiamondsInMap;
  704.     
  705.         // 108 = length of meter; 17 = offset from start of meter
  706.     SetRect(&meterRect, 17, 2, (108 * percent) + 17, 14);
  707.     
  708.     
  709.         // Set port to our sprite's framePort GWorld
  710.     SetGWorld(gDiamondMeterSpriteP->curFrameP->framePort, nil);
  711.     
  712.     ForeColor(magentaColor);
  713.     PaintRect(&meterRect);
  714.     
  715.         // IMPORTANT: Set the color back when done! (In case CopyBits is used later)
  716.     ForeColor(blackColor);
  717.     
  718.     
  719.         // Update the pixel mask directly if we are using a pixelMask.
  720.     if (gDiamondMeterSpriteP->frameDrawProc != SWStdSpriteDrawProc)
  721.     {
  722.             // Set port to our sprite's pixel mask GWorld
  723.         SetGWorld(gDiamondMeterSpriteP->curFrameP->maskPort, nil);
  724.         
  725.             // Mask image is inverted when in 8-bit or less
  726.         if (gSpriteWorldP->pixelDepth <= 8)
  727.             ForeColor(whiteColor);
  728.         else
  729.             ForeColor(blackColor);
  730.         
  731.         PaintRect(&meterRect);
  732.         ForeColor(blackColor);
  733.     }
  734.     else
  735.     {
  736.             // Otherwise, use SWUpdateFrameMasks to update the region mask.
  737.         SWUpdateFrameMasks(gDiamondMeterSpriteP->curFrameP);
  738.     }
  739.     
  740.     
  741.         // Set sprite to be redrawn, since we've changed its image
  742.     gDiamondMeterSpriteP->needsToBeDrawn = true;
  743. }
  744.  
  745.  
  746. ///--------------------------------------------------------------------------------------
  747. //  SmoothScrollingWorldMoveProc - our scrolling WorldMoveProc
  748. ///--------------------------------------------------------------------------------------
  749.  
  750. SW_FUNC void SmoothScrollingWorldMoveProc(
  751.     SpriteWorldPtr spriteWorldP,
  752.     SpritePtr followSpriteP)
  753. {    
  754.     short    screenMidRectTop, screenMidRectLeft;
  755.     
  756.     screenMidRectTop = gScreenMidRect.top + spriteWorldP->visScrollRect.top;
  757.     screenMidRectLeft = gScreenMidRect.left + spriteWorldP->visScrollRect.left;
  758.     
  759.     
  760.     spriteWorldP->horizScrollDelta = (kSpriteMoveDelta * 
  761.         (SWGetSpriteHorizLoc(followSpriteP) - screenMidRectLeft) ) / kSpriteMoveDistance;
  762.     
  763.     spriteWorldP->vertScrollDelta = (kSpriteMoveDelta * 
  764.         (SWGetSpriteVertLoc(followSpriteP) - screenMidRectTop) ) / kSpriteMoveDistance;
  765.     
  766.     if (kInterlacedMode)
  767.         spriteWorldP->vertScrollDelta = spriteWorldP->vertScrollDelta>>1<<1;
  768. }
  769.  
  770.  
  771. ///--------------------------------------------------------------------------------------
  772. //  UpdateKeys (Put the latest key values in the keys structure)
  773. ///--------------------------------------------------------------------------------------
  774.  
  775. void    UpdateKeys( void )
  776. {
  777.     EventRecord        event;
  778.     short            theKey;
  779.     Boolean            isDown;
  780.     
  781.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  782.     {
  783.         theKey = (event.message & keyCodeMask) >> 8;
  784.         isDown = (event.what != keyUp);
  785.         
  786.         if ( (theKey == kLeftArrowKey) || (theKey == kLeftKeyPad) )
  787.             gKeys.left = isDown;
  788.         else if ( (theKey == kRightArrowKey) || (theKey == kRightKeyPad) )
  789.             gKeys.right = isDown;
  790.         else if ( (theKey == kDownArrowKey) || (theKey == kDownKeyPad) )
  791.             gKeys.down = isDown;
  792.         else if ( (theKey == kUpArrowKey) || (theKey == kUpKeyPad) )
  793.             gKeys.up = isDown;
  794.     }
  795. }
  796.